package org.finesys.system.service.impl;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.finesys.common.constants.BaseConstant;
import org.finesys.common.constants.CacheConstants;
import org.finesys.common.core.module.R;
import org.finesys.common.excel.exception.ErrorMessage;
import org.finesys.common.mp.core.service.impl.BaseServiceImpl;
import org.finesys.common.security.core.module.AuthUser;
import org.finesys.common.security.core.util.SecurityUtils;
import org.finesys.system.api.dto.DeptDTO;
import org.finesys.system.api.entity.SysDept;
import org.finesys.system.api.entity.SysDeptRelation;
import org.finesys.system.api.vo.DeptExcelVO;
import org.finesys.system.convert.SysDeptConvert;
import org.finesys.system.mapper.SysDeptMapper;
import org.finesys.system.service.SysDeptRelationService;
import org.finesys.system.service.SysDeptService;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.BindingResult;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class SysDeptServiceImpl extends BaseServiceImpl<SysDeptMapper, SysDept> implements SysDeptService {

    private final SysDeptRelationService sysDeptRelationService;

    @Override
    public List<DeptDTO> getDeptTree() {
        //获取所有部门信息
        List<SysDept> allList = findAll();
        //转换
        List<DeptDTO> allDeptList = SysDeptConvert.INSTANCE.convertList(allList);
        //获取父节点为空的节点信息
        List<DeptDTO> rootList = allDeptList.parallelStream().filter(sysDept -> sysDept.getParentId() == null).collect(Collectors.toList());
        if (rootList.isEmpty()) {
            return new ArrayList<>();
        }
        rootList.forEach(deptDTO -> {
            deptDTO.setChildren(getTree(allDeptList, deptDTO.getDeptId()));
        });
        return rootList;
    }

    @Override
    public List<DeptDTO> getUserDeptTree() {
        AuthUser authUser = SecurityUtils.getUser();
        Long deptId = authUser.getDeptId();
        return findChildDepts(deptId);
    }

    @Override
    @CacheEvict(value = CacheConstants.DEPT_DETAILS, allEntries = true)
    public Boolean deleteById(Long id) {
        //查询子节点信息
        List<DeptDTO> newList = findChildDepts(id);
        //本身
        SysDept sysDept = baseMapper.selectById(id);
        newList.add(SysDeptConvert.INSTANCE.convert(sysDept));
        List<Long> deptIds = newList.parallelStream().map(DeptDTO::getDeptId).collect(Collectors.toList());
        //删除本身及其子节点
        if (CollUtil.isNotEmpty(deptIds)) {
            this.removeByIds(deptIds);
        }
        // 删除部门级联关系
        sysDeptRelationService.removeDeptRelationById(id);
        return Boolean.TRUE;
    }

    //根据传入的Id找下级菜单信息
    private List<DeptDTO> getTree(List<DeptDTO> deptList, long rootId) {
        // 遍历所有节点，将所有菜单的父id与传过来的根节点的id比较,相等说明：为该根节点的子节点。
        List<DeptDTO> rootMenu = deptList.stream().filter(sysDept -> sysDept.getParentId() == rootId).collect(Collectors.toList());
        rootMenu.stream().forEach(deptDTO -> {
            deptDTO.setChildren(getChildList(deptList, deptDTO));
        });
        return rootMenu;
    }

    //根据传入的parentDept找下级菜单信息
    private List<DeptDTO> getChildList(List<DeptDTO> deptList, DeptDTO parentDept) {
        //菜单ID
        long rootId = parentDept.getDeptId();
        // 遍历所有节点，将所有菜单的父id与传过来的根节点的id比较,相等说明：为该根节点的子节点。
        List<DeptDTO> childDeptList = deptList.stream().filter(sysDept -> sysDept.getParentId() == rootId).collect(Collectors.toList());
        //如果节点下没有子节点，返回一个空List（递归退出）
        if (childDeptList.isEmpty()) {
            return new ArrayList<>();
        }
        //循环子菜单，递归查询子菜单的子菜单
        childDeptList.stream().forEach(deptDTO -> {
            deptDTO.setChildren(getChildList(deptList, deptDTO));
        });
        return childDeptList;
    }

    @Override
    @CacheEvict(value = CacheConstants.DEPT_DETAILS, allEntries = true)
    public Boolean addDept(DeptDTO deptDTO) {
        SysDept sysDept = SysDeptConvert.INSTANCE.convert(deptDTO);
        this.save(sysDept);
        sysDeptRelationService.saveDeptRelation(sysDept);
        return Boolean.TRUE;
    }


    @Override
    public DeptDTO getDeptById(Long id) {
        return SysDeptConvert.INSTANCE.convert(this.getOne(Wrappers.<SysDept>lambdaQuery().eq(SysDept::getDeptId, id)));
    }

    @Override
    @CacheEvict(value = CacheConstants.DEPT_DETAILS, allEntries = true)
    public Boolean updateById(DeptDTO deptDTO) {
        SysDept sysDept = SysDeptConvert.INSTANCE.convert(deptDTO);
        this.updateById(sysDept);
        // 更新部门关系
        SysDeptRelation relation = new SysDeptRelation();
        relation.setAncestor(sysDept.getParentId());
        relation.setDescendant(sysDept.getDeptId());
        sysDeptRelationService.updateDeptRelation(relation);
        return Boolean.TRUE;
    }

    @Override
    public List<DeptDTO> findChildDepts(long deptId) {
        //查询全部部门信息
        List<SysDept> allDeptList = baseMapper.selectList(Wrappers.emptyWrapper());
        //转换
        List<DeptDTO> deptList = SysDeptConvert.INSTANCE.convertList(allDeptList);
        //存放最后的返回集合信息
        List<DeptDTO> newList = new ArrayList<>();
        getChildList(newList, deptList, deptId);
        //根据传入的Id找下级菜单信息
        return newList;
    }

    //根据所有部门信息，及其父节点，组装新的部门节点集合
    private void getChildList(List<DeptDTO> newList, List<DeptDTO> allDeptList, long deptId) {
        //查询子节点
        List<DeptDTO> childList = allDeptList.stream().filter(deptDTO -> {
            if (ObjectUtils.isEmpty(deptDTO.getParentId())) {
                return false;
            } else {
                return Objects.equals(deptId, deptDTO.getParentId());
            }
        }).collect(Collectors.toList());
        if (childList.isEmpty()) {
            return;
        }
        //加入结果集
        newList.addAll(childList);
        //继续递归循环处理
        childList.stream().forEach(deptDTO -> {
            getChildList(newList, allDeptList, deptDTO.getDeptId());
        });
    }

    /**
     * 获取当前用户部门(包含父级)
     *
     * @return 用户所处部门
     */
    @Override
    public String getDeptNameByUserId() {
        AuthUser authUser = SecurityUtils.getUser();
        Long deptId = authUser.getDeptId();
        SysDept sysDept = baseMapper.selectById(deptId);
        List<SysDept> parentList = new ArrayList<>();
        //添加当前部门信息
        parentList.add(sysDept);
        //获取父部门信息
        getParentDept(sysDept, parentList);
        //拼接字符串
        String deptName = "";
        for (int i = parentList.size() - 1; i > 0; i--) {
            deptName = deptName + "-" + parentList.get(i).getDeptName();
        }
        return deptName;
    }

    /**
     * 避免sql支持不同，无法使用统一的sql，用代码来实现递归操作
     */
    private void getParentDept(SysDept sysDept, List<SysDept> parentList) {
        if (Objects.nonNull(sysDept.getParentId())) {
            SysDept parentDept = baseMapper.selectById(sysDept.getParentId());
            if (Objects.nonNull(parentDept)) {
                parentList.add(parentDept);
                getParentDept(parentDept, parentList);
            }
        }
    }

    /**
     * 查询全部部门树
     *
     * @param deptName
     * @return 树 部门名称
     */
    @Override
    @Cacheable(value = CacheConstants.DEPT_DETAILS, key = "#deptName", condition = "#deptName!=null and #depthName!=''", unless = "#result==null or #result.isEmpty()")
    public List<Tree<Long>> selectTree(String deptName) {
        // 查询全部部门
        List<SysDept> deptAllList = baseMapper
                .selectList(Wrappers.<SysDept>lambdaQuery().like(StrUtil.isNotBlank(deptName), SysDept::getDeptName, deptName));

        // 权限内部门
        List<TreeNode<Long>> collect = deptAllList.stream()
                .filter(dept -> dept.getDeptId().intValue() != dept.getParentId())
                .sorted(Comparator.comparingInt(SysDept::getSortOrder))
                .map(dept -> {
                    TreeNode<Long> treeNode = new TreeNode<>();
                    treeNode.setId(dept.getDeptId());
                    treeNode.setParentId(dept.getParentId());
                    treeNode.setName(dept.getDeptName());
                    treeNode.setWeight(dept.getSortOrder());
                    // 有权限不返回标识
                    Map<String, Object> extra = new HashMap<>(8);
                    extra.put("createTime", dept.getCreateTime());
                    treeNode.setExtra(extra);
                    return treeNode;
                })
                .collect(Collectors.toList());

        // 模糊查询 不组装树结构 直接返回 表格方便编辑
        if (StrUtil.isNotBlank(deptName)) {
            return collect.stream().map(node -> {
                Tree<Long> tree = new Tree<>();
                tree.putAll(node.getExtra());
                BeanUtils.copyProperties(node, tree);
                return tree;
            }).collect(Collectors.toList());
        }

        return TreeUtil.build(collect, 0L);
    }

    @Override
    @CacheEvict(value = CacheConstants.DEPT_DETAILS, allEntries = true)
    public R<?> sync() {
        return R.success();
    }

    @Override
    public R<?> importExcel(List<DeptExcelVO> excelVOList, BindingResult bindingResult) {
        List<ErrorMessage> errorMessageList = (List<ErrorMessage>) bindingResult.getTarget();

        List<SysDept> deptList = this.list();
        for (DeptExcelVO item : excelVOList) {
            Set<String> errorMsg = new HashSet<>();
            boolean exsitUsername = deptList.stream().anyMatch(sysDept -> item.getDeptName().equals(sysDept.getDeptName()));
            if (exsitUsername) {
                errorMsg.add("部门名称已经存在");
            }
            SysDept one = this.getOne(Wrappers.<SysDept>lambdaQuery().eq(SysDept::getDeptName, item.getParentName()));
            if (item.getParentName().equals("根部门")) {
                one = new SysDept();
                one.setDeptId(0L);
            }
            if (one == null) {
                errorMsg.add("上级部门不存在");
            }
            if (CollUtil.isEmpty(errorMsg)) {
                SysDept sysDept = new SysDept();
                sysDept.setDeptName(item.getDeptName());
                sysDept.setParentId(one==null?BaseConstant.DEPT_ROOT_ID:one.getDeptId());
                sysDept.setSortOrder(item.getSortOrder());
                baseMapper.insert(sysDept);
            } else {
                // 数据不合法情况
                errorMessageList.add(new ErrorMessage(item.getLineNum(), errorMsg));
            }
        }
        if (CollUtil.isNotEmpty(errorMessageList)) {
            return R.failed(errorMessageList);
        }
        return R.success(null, "部门导入成功");
    }

    @Override
    public List<DeptExcelVO> listDept() {
        List<SysDept> sysDepts = this.list();
        return sysDepts.stream().map(sysDept -> {
            DeptExcelVO deptExcelVO = SysDeptConvert.INSTANCE.convertExcelVO(sysDept);
            Optional<String> first = sysDepts.stream().filter(dept -> dept.getDeptId().equals(sysDept.getParentId())).map(SysDept::getDeptName).findFirst();
            deptExcelVO.setParentName(first.orElse("根部门"));
            return deptExcelVO;
        }).collect(Collectors.toList());
    }
}
